<template>
	<view class="vi_checkbox"
		:class="mainClass"
		:style="mainStyle"
		hover-class="vi_checkbox_hover"
		@click="checkboxClick">
		<view :style="{'order':iconReverse?2:1}" v-if="!buttonMode">
			<vi-style-controller
				compName="checkbox"
				hoverClass="none"
				:size="setting.size"
				:type="setting.type"
				:color="color"
				:radius="isRadio?'circle':'square'"
				:width="setting.size?'':'1.2em'"
				:height="setting.size?'':'1.2em'"
				:borderWidth="1"
				:plain="plain"
				:disabled="inDisabled"
				:readOnly="inReadOnly||isLocked"
				inline
				borderBox
				textHide
				:active="inChecked"
				basicBorder>
				<text class="iconfont" :class="iconSetting.checked"></text>
			</vi-style-controller>
		</view>
		<view :style="{'order':iconReverse?1:2, 'margin-left':'0.5em'}" v-if="!buttonMode">
			<slot />
		</view>
		<!-- 方块模式 -->
		<vi-style-controller v-if="buttonMode"
			compName="checkboxButton"
			:size="setting.size"
			:type="setting.type"
			:color="color"
			:radius="setting.radius"
			:width="setting.width"
			:height="setting.height"
			:borderWidth="1"
			:plain="plain"
			:disabled="inDisabled"
			:readOnly="inReadOnly||isLocked"
			inline
			borderBox
			:active="inChecked"
			basicBorder>
			<view :style="{'padding':setting.width?'':'0 0.5em'}">
				<slot />
			</view>
		</vi-style-controller>
	</view>
</template>

<script>
	export default {
		name:"viCheckbox",
		options:{//样式穿透，微信须设置
			styleIsolation: "shared"
		},
		model:{
			prop:"value",
			event:"input"
		},
		props:{
			type:{
				type:[String,null],
				default:null
			},
			color:{
				type:[String,null],
				default:""
			},
			//预设尺寸,sm、md、lg
			size:{
				type:[String,null],
				default:null
			},
			//是否镂空
			plain:{
				type:[Boolean,null],
				default:false
			},
			//内联排版
			inline:{
				type:[Boolean,null],
				default:null
			},
			value:{
				type:[String,Number,null],
				default:""
			},
			checked:{
				type:[Boolean,null],
				default:false
			},
			groupId:{
				type:[String,null],
				default:""
			},
			//框与slot对齐
			align:{
				type:[String,null],
				default:""
			},
			//复选框置于右侧
			iconReverse:{
				type:[Boolean,null],
				default:false
			},
			disabled:{
				type:[Boolean,null],
				default:false
			},
			//只读，不可点击，只能系统更改
			readOnly:{
				type:[Boolean,null],
				default:false
			},
			//禁用时点击提示消息
			disabledMsg:{
				type:[String,null],
				default:""
			},
			//只读时点击提示消息
			readOnlyMsg:{
				type:[String,null],
				default:""
			},
			icon:{
				type:[Object,null],
				default:()=>({})
			},
			//方块宽度，设置后取消默认内边距
			width:{
				type:[String,null],
				default:""
			},
			//按钮高度
			height:{
				type:[String,null],
				default:""
			},
			//圆角
			radius:{
				type:[String,Number,null],
				default:null
			}
		},
		data() {
			return {
				isGroup:false,
				isRadio:false,
				isLocked:false,
				inChecked:false,
				inDisabled:false,
				inReadOnly:false,
				//复选框序列，影响圆角。由组控制
				isFirst:false,
				isCenter:false,
				isLast:false,
				buttonMode:false,	//方块模式，由组控制
				buttonWidth:"",		//方块统一宽，由组控制，优先级小于width
				buttonHeight:"",		//方块统一高，由组控制，优先级小于height
				buttonRadius:null,		//方块统一圆角，由组控制，优先级小于radius
				dicAlign:{
					left:"flex-start",
					right:"flex-end",
					center:"center",
					between:"space-between",
					evenly:"space-evenly"
				},
				dicIcon:{
					checked:"icon-checked"
				}
			}
		},
		computed:{
			//将默认值内含到css、计算属性等地方，只内含真值
			//规避特殊使用的情况下，由prop传入undefined、null等无效数据导致的，默认值失效问题。例如组件嵌套且需要组件间参数传递
			//HBuilder X3.3.13; 微信开发者工具stable 1.05.2111300
			//微信小程序会对传入的undefined、null值根据参数类型输出不同空值(false、""、null、0)，参数类型为null或未指定参数类型则输出null
			//H5会对传入的undefined取默认值，未设默认值则输出undefined。对传入的null值固定输出null
			//做参数传递时需警惕两者行为不同而造成的陷阱，主要问题出现在微信小程序的空值转化，输出非用户传入的空值、假值，使默认真值丢失
			//兼容空值取默认值的可行方案目前为，参数类型加入null如[Boolean,null]，判断传入参数是否为定义的类型，是则使用，否则赋予默认值
			setting(){
				return {
					type: this.$api.isDefined(this.type)? this.type :"primary",
					size: this.$api.isDefined(this.size)? this.size :"md",
					radius: this.$api.isDefined(this.radius)?this.radius:(this.$api.isDefined(this.buttonRadius)?this.buttonRadius:"circle"),
					width: this.width || this.buttonWidth,
					height: this.height || this.buttonHeight,
					align: this.align ||"left",
					inline: this.$api.isBoolean(this.inline)? this.inline :true,
				}
			},
			mainClass(){
				let res ="";
				if(this.buttonMode){
					res += this.isFirst? "vi_checkbox_first " :"";
					res += this.isLast? "vi_checkbox_last " :"";
					res += this.isCenter? "vi_checkbox_center " :"";
				}
				return res
			},
			mainStyle(){
				let res ={
					"align-items":"center"
				};
				let inline = this.setting.inline;
				if(inline){
					res["display"] = "inline-flex";
				}else{
					res["display"] = "flex";
					res["width"] = "100%";
				}
				let align = this.setting.align;
				res["justify-content"] = this.dicAlign[align]? this.dicAlign[align]: this.dicAlign.left;
				return this.$api.objToStr(res)
			},
			iconSetting(){
				if(this.$api.isObject(this.icon)){
					return Object.assign({},this.dicIcon,this.icon)
				}
				return this.dicIcon
			}
		},
		methods: {
			getValue(){//返回当前value，上层组用
				let val = this.value;
				return val||val===0?val:""
			},
			//设置选中，上层组全选功能、组数据变更用
			setCheck(value, force){
				if((!this.inDisabled && !this.inReadOnly)||force){
					this.inChecked = value;
					return this.$api.isValue(this.value)? this.value :true;
				}else{//如果组件为disabled，readOnly 值不可更改，返回修改失败做后续处理
					return false
				}
			},
			//设置可用，如果存在组，根据组及当前组件设置可用，两者均可用时，组件可用
			setDisabled(){
				if(this.isGroup){
					let group = this.getGroup();
					if(group){
						this.inDisabled = group.getDisabled() || this.disabled;
						this.inReadOnly = group.getReadOnly() || this.readOnly;
					}
				}else{
					this.inDisabled = this.disabled;
					this.inReadOnly = this.readOnly;
				}
			},
			//设置方块模式，组使用
			setButtonMode(options){
				let {buttonMode, width, height, radius, first, center, last} = options;
				this.buttonMode = buttonMode;
				this.buttonWidth = width;
				this.buttonHeight = height;
				this.buttonRadius = radius;
				this.isFirst = first;
				this.isCenter = center;
				this.isLast = last;
			},
			//点击
			checkboxClick(){
				if(this.inDisabled){
					//提示禁用信息
					if(this.disabledMsg){
						this.$api.msg(this.disabledMsg, "info")
					}
					return
				}
				if(this.inReadOnly){
					//提示只读信息
					if(this.readOnlyMsg){
						this.$api.msg(this.readOnlyMsg, "info")
					}
					return
				}
				//如果存在组，值变更交由组处理
				if(this.isGroup){//向组提交数据，添加还是删除
					let group = this.getGroup();
					if (group){
						let res = group.checkboxChange(this.value, !this.inChecked);
						if(res){//修改成功，组件状态为非锁定（用于显示）
							this.isLocked = false
						}else{//修改失败，组件状态为锁定（用于显示）
							this.isLocked = true
						}
					}
				}else{
					this.inChecked = !this.inChecked;
				}
				this.$emit("input", this.inChecked);
				this.$emit("change", this.inChecked);
			},
			//检查组
			getGroup(){
				return this.$api.getParent(this, "viCheckboxGroup", "groupId")
			},
		},
		watch:{
			"disabled": {
				handler(newVal) {
					this.setDisabled()
				}
			},
			"readOnly": {
				handler(newVal) {
					this.setDisabled()
				}
			},
			"checked":{
				immediate:true,
				handler(newVal) {
					this.inChecked = !!newVal
				}
			}
		},
		created() {
			this.contentId = `el${Math.ceil(Math.random() * 10e10).toString(36)}`;
			//检查组
			if(this.groupId){//如果存在组，检查组是否存在当前值
				let group = this.getGroup();
				if(group){
					this.isGroup = true;
					this.isRadio = group.isRadio;
				}
			}
			//设置可用
			this.setDisabled();
		}
	}
</script>

<style lang="scss">
//扩展至点击文字也激活禁用色
.vi_checkbox.vi_checkbox_hover /deep/.vi_styleController.disabled.vi_disBor{ border-color: $vi-color-error;}
.vi_checkbox.vi_checkbox_hover /deep/.vi_styleController.readOnly.vi_readBor{ border-color: $vi-color-error;}
// 方块模式
.vi_checkbox_first /deep/>.vi_styleController{ border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important;}
.vi_checkbox_center /deep/>.vi_styleController{ border-radius: 0 !important;}
.vi_checkbox_last /deep/>.vi_styleController{ border-top-left-radius: 0 !important; border-bottom-left-radius: 0 !important;}
</style>
